package com.yonyougov.devops.monitor.task;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.yonyougov.devops.monitor.dao.ServerInfoRepository;
import com.yonyougov.devops.monitor.dto.ServerInfoRequestDto;
import com.yonyougov.devops.monitor.entity.ServerInfo;
import com.yonyougov.devops.monitor.util.EmailSender;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class MonitorTask implements ApplicationListener<ContextRefreshedEvent> {

    @Value("${monitor.threshold.duration}")
    private int duration;
    @Value("${monitor.mail.receiver}")
    private String receiver;
    @Value("${monitor.notice.url}")
    private String noticeUrl;

    private ServerInfoRepository serverInfoRepository;
    private EmailSender emailSender;

    RestTemplate restTemplate = new RestTemplate();

    private ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor((
            new ThreadFactoryBuilder()).setNameFormat("Monitor task %d").build());

    public MonitorTask(ServerInfoRepository serverInfoRepository, EmailSender emailSender) {
        this.serverInfoRepository = serverInfoRepository;
        this.emailSender = emailSender;
    }

    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        this.executorService.scheduleAtFixedRate(() -> {
            log.info("Monitor task is scheduling");

            List<ServerInfoRequestDto> dtoList = getServerInfoRequestDtoData();

            if (dtoList.isEmpty()) {
                log.info("ServerInfo list is empty ");
                return;
            }
            updateServerStatus(dtoList);

        }, 60L, duration * 60L, TimeUnit.SECONDS);
    }

    private List<ServerInfoRequestDto> getServerInfoRequestDtoData() {
        Iterable<ServerInfo> serverInfos = serverInfoRepository.findAll();

        List<ServerInfoRequestDto> dtoList = new LinkedList<>();
        List<String> hostname = new LinkedList<>();

        serverInfos.iterator().forEachRemaining(s -> {
            ServerInfoRequestDto dto = new ServerInfoRequestDto();
            dto.setHostname(s.getHostname());
            if (new Date().getTime() - s.getDate().getTime() > duration * 60000) {
                dto.setState(0);
                hostname.add(s.getHostname());
                log.info("server {} is over {} minutes", s.getHostname(), duration);
            } else {
                dto.setState(1);
            }
            dtoList.add(dto);
        });
        sendNotice(hostname);
        return dtoList;
    }

    private void sendNotice(List<String> hostname) {
        if (hostname.isEmpty()) {
            return;
        }
        String subject = "【监控报警】服务器" + String.join("、", hostname) + "超过" + duration + "分钟未收到监控数据";
        String text = String.join("、", hostname) + "超过" + duration + "分钟未收到监控数据，请确认！";
        emailSender.sendEmail(receiver.split(","), subject, text);
    }

    private void updateServerStatus(List<ServerInfoRequestDto> dtoList) {
        Map<String, List<ServerInfoRequestDto>> request = new HashMap<>();
        request.put("serverList", dtoList);

        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
        headers.setContentType(type);
        headers.add("Accept", MediaType.APPLICATION_JSON.toString());

        ObjectMapper objectMapper = new ObjectMapper();
        try {
            log.debug("request paras: {}", objectMapper.writeValueAsString(request));
            HttpEntity<String> formEntity = new HttpEntity<>(objectMapper.writeValueAsString(request), headers);
            restTemplate.postForEntity(noticeUrl + "/crux-cisupport/api/v2/server/u/status", formEntity, String.class);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }
}
